using System;
using System.Windows.Forms;
using TagTool.Core;
using TagTool.Devices;
using TagTool.Devices.Midi;
using TagTool.GraphicTypes;

namespace TagTool.Nodes.Devices
{
    /**
     * This node type makes Midi access for tagtool networks available.
     */
    public class MidiControlNode : BaseNode
    {
        private MidiInputDevice midi;
        static Form f = new Form();

        private InputSlot port;
        double dPort;

        private InputSlot note;
        private OutputSlot velocity;

        /**
         * Constructor.
         */
        public MidiControlNode() : base()
        {
            port = new InputSlot(this, "Port", 0.0);
            port.ParseCallback = ParseHelper.ParseDouble;
            dPort = 0.0;
            
            note = new InputSlot(this, "Control number", 0.0);           
            note.ParseCallback = ParseHelper.ParseDouble;

            velocity = new OutputSlot(this, "Value", typeof(double));
            
            IntPtr x = f.Handle;
            
            midi = (MidiInputDevice)MidiManager.Instance.GetDevice(Convert.ToInt32((double)port.Value));
            
            if (midi != null)
            {
	            midi.ControlChangeEvent += new ControlChangeEventHandler(OnControlChangeEvent);
	            if (!midi.Connected)
	            {
	            	midi.Connect();
	            }
	            Name = "Midi Control (present)";
            }
            else
            {
            	Name = "Midi Control (not present)";
            }
            
            velocity.Value = 0.0;           
        }

        ~MidiControlNode()
        {
            if (midi != null)
            {
            	midi.Disconnect();
            }
        }

        public override void Update(Object sender)
        { // do nothing to update
            if (dPort != (double)port.Value)
            {
            	if (midi != null)
            	{
                	midi.Disconnect();
                	midi.ControlChangeEvent -= new ControlChangeEventHandler(OnControlChangeEvent);
            	}
                midi = (MidiInputDevice)MidiManager.Instance.GetDevice(Convert.ToInt32((double)port.Value));
				
                if (midi != null)
            	{
	                midi.Connect();
	                midi.ControlChangeEvent += new ControlChangeEventHandler(OnControlChangeEvent);
	                Name = "Midi Control (present)";
                }
                else
                {
                	Name = "Midi Control (not present)";
                }
                
                dPort = (double)port.Value;
            }
        }

        [NodeAttribute(SlotType.Input, Show = true)]
        public InputSlot Port
        {
            get { return port; }
        }

        [NodeAttribute(SlotType.Input, Show = true)]
        public InputSlot Note
        {
            get { return note; }
        }

        [NodeAttribute(SlotType.Output, Show = true)]
        public OutputSlot Velocity
        {
            get { return velocity; }
        }
        
        private void OnControlChangeEvent(object sender, MidiDeviceEventArgs e)
        {
            f.Invoke(new ControlChangeEventHandler(ParseControlChangeArgs), sender, e);
        }

        private void ParseControlChangeArgs(object sender, MidiDeviceEventArgs e)
        {
            ControlChangeMessage msg = (ControlChangeMessage)e.ChannelMessage;
            if (msg.Controller == Convert.ToInt32((double)note.Value))
            {
                velocity.Value = (double)msg.Value;
                CastTrigger();
            }
        }
  
    }
}
